using System;
using System.IO;
using System.Windows.Forms;
using System.Collections;

using EA;

namespace OpenEdge.DatabaseEngineering.Generate
{
	/// <summary>
	/// Summary description for Class1.
	/// </summary>
	public class Generator
	{
		public delegate void WriteRequest(string messageString);
		public delegate void ProgressEvent(int number);
		public delegate void CompleteEvent();

		public event WriteRequest		LogWriteLine;
		public event WriteRequest		DefinitionWriteLine;

		public event ProgressEvent		initializeProgress;
		public event ProgressEvent	    updateProgress;
		public event CompleteEvent		generateComplete;

		private Repository eaRepository;


		public Generator(EA.Repository eaRepository) 
		{
			this.eaRepository = eaRepository;
		}

		public void generate() 
		{			

			string objectType = this.eaRepository.GetTreeSelectedItemType().ToString();

			Object  currentObject;
			Package currentPackage;
			Element currentElement;

			this.eaRepository.GetTreeSelectedItem(out currentObject);

			switch(objectType)
			{
				case "otPackage":				
					currentPackage = (Package) currentObject;					
					processPackage(currentPackage);
					break;				
				case "otElement":
					currentElement = (Element) currentObject;
					processElement(currentElement);
					break;
				default:
					break;
			}

			//System.IO.File.Copy(@"c:\\OpenEdgeMDGWork\\arc\\humanresources.df", @"c:\\OpenEdgeMDGWork\\humanresources.df", true);
			

		}

		void processPackage(Package currentPackage) 
		{
			this.LogWriteLine("Initializing...");

			this.initializeProgress(currentPackage.Elements.Count);

			/*
			for (short idx = 0; idx < currentPackage.Packages.Count; idx++)
			{
				Package childPackage = (Package) currentPackage.Packages.GetAt(idx);
				processPackage(childPackage);
			}
			*/

			for (short idx = 0; idx < currentPackage.Elements.Count; idx++) 
			{				
				Element childElement = (Element) currentPackage.Elements.GetAt(idx);
				if (childElement.Type == "Object")
					processElement(childElement);

			}

			for (short idx = 0; idx < currentPackage.Elements.Count; idx++) 
			{				
				Element childElement = (Element) currentPackage.Elements.GetAt(idx);
				if (childElement.Type == "Class")
					processElement(childElement);

			}

			this.generateComplete();
		}

		void processElement(Element currentElement) 
		{
			switch (currentElement.Type)
			{
				case "Class":
					if (currentElement.Stereotype == "table")
						this.processTable(currentElement);
					break;
				case "Object":
					if (currentElement.Stereotype == "Sequence")
						this.processSequence(currentElement);
					break;
				default:
					break;
			}

		}

		void processTable(Element currentElement) 
		{
			
			string logString = "Adding Table \""  + currentElement.Name + "\"";
			
			this.LogWriteLine(logString);

			string definitionString = "ADD TABLE \"" + currentElement.Name + "\"";
			this.DefinitionWriteLine(definitionString);

			if (currentElement.Tablespace != "")
				definitionString = "  AREA \"" + currentElement.Tablespace + "\"";
			else
				definitionString = "  AREA \"Schema Area\"";

			this.DefinitionWriteLine(definitionString);

			definitionString = "  DESCRIPTION \"" + currentElement.Notes + "\"";
			this.DefinitionWriteLine(definitionString);

			EA.TaggedValue currentTaggedValue = (EA.TaggedValue) currentElement.TaggedValues.GetByName("DUMP-NAME");
			if (currentTaggedValue != null) 
			{
				definitionString = "  DUMP-NAME \"" + currentTaggedValue.Value + "\"";
				this.DefinitionWriteLine(definitionString);
			}


			for (short idx = 0; idx < currentElement.Methods.Count; idx++)
			{
				EA.Method currentMethod = (EA.Method) currentElement.Methods.GetAt(idx);
				if (currentMethod.Stereotype == "trigger")
				{
					definitionString = "  TABLE-TRIGGER \"" + currentMethod.Name.ToUpper() + "\"";
					
					/*
					EA.MethodTag currentMethodTag = (EA.MethodTag) currentMethod.TaggedValues.GetByName("OVERRIDE");
					if (currentMethodTag != null)
					{
						if (currentMethodTag.Value == "yes")
							definitionString += " OVERRIDE";
						else
							definitionString += " NO-OVERRIDE";
					}
					*/
					foreach(EA.MethodTag currentMethodTag in currentMethod.TaggedValues)
					{
						if (currentMethodTag.Name == "OVERRIDE")
						{
							if (currentMethodTag.Value == "yes")
								definitionString += " OVERRIDE";
							else
								definitionString += " NO-OVERRIDE";
							break;
						}
					}

					/*
					currentMethodTag = (EA.MethodTag) currentMethod.TaggedValues.GetByName("PROCEDURE");
					if (currentMethodTag != null)
					{
						definitionString += " PROCEDURE \"" + currentMethodTag.Value + "\"";
					}
					*/
					foreach(EA.MethodTag currentMethodTag in currentMethod.TaggedValues)
					{
						if (currentMethodTag.Name == "PROCEDURE")
						{
							definitionString += " PROCEDURE \"" + currentMethodTag.Value + "\"";
							break;
						}
					}

					/*
					currentMethodTag = (EA.MethodTag) currentMethod.TaggedValues.GetByName("CRC");
					if (currentMethodTag != null)
					{
						definitionString += " CRC \"";
						if (currentMethodTag.Value == "")
							definitionString += "\"";
						else
							definitionString += currentMethodTag.Value + "\"";
					}
					*/
					foreach(EA.MethodTag currentMethodTag in currentMethod.TaggedValues)
					{
						if (currentMethodTag.Name == "CRC")
						{
							definitionString += " CRC \"";
							if (currentMethodTag.Value == "")
								definitionString += "\"";
							else
								definitionString += currentMethodTag.Value + "\"";
							break;
						}
					}

					this.DefinitionWriteLine(definitionString);
					this.LogWriteLine(definitionString);

				}
			}
			this.DefinitionWriteLine("");

			foreach(EA.Attribute currentAttribute in currentElement.Attributes)
			{
				if (currentAttribute.Stereotype == "field")
					processField(currentElement, currentAttribute);
			}
			
			foreach(EA.Method currentMethod in currentElement.Methods)
			{
				if (currentMethod.Stereotype == "index" || currentMethod.Stereotype == "unique" || currentMethod.Stereotype == "PK")
					processIndex(currentElement, currentMethod);
			}

			this.updateProgress(1);
		}

		void processField(EA.Element currentElement, EA.Attribute currentAttribute)
		{

			String varType = "";			
			//int varLength  = System.Convert.ToInt16(currentAttribute.Length);
			// int varLength  = 8;
			switch(currentAttribute.Type)
			{
				case "VARCHAR":
					varType = "CHARACTER";
					break;
				case "TEXT":
					varType = "CHARACTER";
					// varLength = 255;
					break;
				case "TIME":
					varType = "INTEGER";
					break;
				default:
					varType = currentAttribute.Type;
					break;
			}

			String varName = currentAttribute.Name.ToLower();
			switch(varName)
			{
				case "title":
					varName = currentElement.Name + "_" + varName;
					break;
				case "keyword":
					varName = currentElement.Name + "_" + varName;
					break;
				default:
					break;
			}
			if (varName.Length > 32) 
				varName = varName.Substring(1,32);

			string logString = "Adding Field \""  + varName + "\" to Table \"" + currentElement.Name + "\" as " + varType;
			
			this.LogWriteLine(logString);

			/*
			logString = " -- " + currentAttribute.Pos.ToString();
			this.LogWriteLine(logString);
			*/

			string definitionString = "ADD FIELD \"" + varName + "\" OF \"" + currentElement.Name + "\" AS " + varType;
			this.DefinitionWriteLine(definitionString);

			if (currentAttribute.TaggedValues.Count > 0)
			{
				foreach(EA.AttributeTag currentAttributeTag in currentAttribute.TaggedValues)
				{	
					definitionString = "  ";
					switch(currentAttributeTag.Name)
					{
						case "INITIAL":
							if (varType == "CHARACTER")
								definitionString += currentAttributeTag.Name + " \"" + currentAttributeTag.Value + "\"";
							else
								definitionString += currentAttributeTag.Name + " " + currentAttributeTag.Value;
							break;
						case "DESCRIPTION":
						case "FORMAT":
							definitionString += currentAttributeTag.Name + " \"" + currentAttributeTag.Value + "\"";							
							break;	
						case "HELP":
						case "LABEL":
						case "COLUMN-LABEL":
						case "VALMSG":
						case "VALEXP":
							definitionString += currentAttributeTag.Name + " \"" + currentAttributeTag.Value + "\"";							
							break;	
						default:
							definitionString += currentAttributeTag.Name + " " + currentAttributeTag.Value;						
							break;
					}
					this.DefinitionWriteLine(definitionString);
				}
			}
			else
			{
				String initialValue = "";
				if (currentAttribute.Default != "NULL")
					initialValue = currentAttribute.Default;
				else
					initialValue = "";

				if (initialValue != "")
				{
					if (varType == "CHARACTER")
						definitionString = "  INITIAL " + " \"" + initialValue + "\"";
					else
						definitionString = "  INITIAL " + initialValue;
					this.DefinitionWriteLine(definitionString);
				}

				definitionString = "  DESCRIPTION " + "\"" + currentAttribute.Notes + "\"";
				this.DefinitionWriteLine(definitionString);

				/*
				definitionString = "";
				if (varType == "CHARACTER")
					definitionString = "  FORMAT " + "\"x(" + varLength.ToString() + ")\"";
				else if (varType == "INTEGER")
					definitionString = "  FORMAT " + "\"->,>>>,>>9\"";
				else if (varType == "DECIMAL")
					definitionString = "  FORMAT " + "\"->>,>>9.99\"";
				else if (varType == "DATE")
					definitionString = "  FORMAT " + "\"99/99/99\"";
				else if (varType == "DATETIME")
					definitionString = "  FORMAT " + "\"99/99/9999 HH:MM:SS\"";
				else if (varType == "BOOL")
					definitionString = "  FORMAT " + "\"yes/no\"";
				this.DefinitionWriteLine(definitionString);
				*/
				
				definitionString = "  LABEL \"" + varName + "\"";
				this.DefinitionWriteLine(definitionString);
			}
			this.DefinitionWriteLine("");

		}


		void processIndex(EA.Element currentElement, EA.Method currentMethod)
		{
			String methodName = currentMethod.Name.ToLower();
			if (methodName.Length > 32)
				methodName = methodName.Substring(1,32);

			string logString = "Adding Index \""  + methodName + "\" to Table \"" + currentElement.Name + "\"";
			
			this.LogWriteLine(logString);

			string definitionString = "ADD INDEX \"" + methodName + "\" ON \"" + currentElement.Name + "\"";
			this.DefinitionWriteLine(definitionString);

			foreach(EA.MethodTag currentMethodTag in currentMethod.TaggedValues)
			{
				definitionString = "  ";
				switch(currentMethodTag.Name)
				{
					case "AREA":
						definitionString += currentMethodTag.Name + " \"" + currentMethodTag.Value + "\"";
						break;
					case "WORD":
					case "UNIQUE":						
					case "PRIMARY":
						definitionString += currentMethodTag.Name;
						break;	
					default:
						definitionString += currentMethodTag.Name + " " + currentMethodTag.Value;						
						break;
				}
				this.DefinitionWriteLine(definitionString);
			}

			foreach(EA.Parameter currentParameter in currentMethod.Parameters)
			{
				String paramName = currentParameter.Name.ToLower();
				switch(paramName)
				{
					case "title":
						paramName = currentElement.Name + "_" + paramName;
						break;
					case "keyword":
						paramName = currentElement.Name + "_" + paramName;
						break;
					default:
						break;
				}
				if (paramName.Length > 32) 
					paramName = paramName.Substring(1,32);

				definitionString = "  INDEX-FIELD \"" + paramName + "\" " + currentParameter.Notes;
				this.DefinitionWriteLine(definitionString);
			}

			this.DefinitionWriteLine("");
			
		}

		void processSequence(Element currentElement) 
		{
			string logString = "Adding Sequence \""  + currentElement.Name + "\"";
			
			this.LogWriteLine(logString);

			string definitionString = "ADD SEQUENCE \"" + currentElement.Name + "\"";
			this.DefinitionWriteLine(definitionString);

			for (short idx = 0; idx < currentElement.Attributes.Count; idx++)
			{
				EA.Attribute currentAttribute = (EA.Attribute) currentElement.Attributes.GetAt(idx);
				definitionString = "  " + currentAttribute.Name.ToUpper() + " " + currentAttribute.Default;
				this.DefinitionWriteLine(definitionString);
			}
			this.DefinitionWriteLine("");

			this.updateProgress(1);

		}

	}
}
